/*
 *  mkcryptomfs.c
 *  cryptomfs
 *
 * Copyright (C) 2008-2009  Greg J. Hedlund
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define _GNU_SOURCE

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <sys/stat.h>
#include <glib.h>
#include "cryptomfsconfig.h"

static gchar *rootpath = NULL;
static gchar *cipher = NULL;
static gchar *md = NULL;
static gchar *volume_name = NULL;
static gchar *custom_icon = NULL;
static gchar *mountpoint = NULL;
static gint blocksize = -1;
static gint salts = -1;

static GOptionEntry entries[] = 
{
{ "blocksize", 0, 0, G_OPTION_ARG_INT, &blocksize, "Set blocksize to BS (default 2048)", "<blocksize:int>" },
{ "cipher", 0, 0, G_OPTION_ARG_STRING, &cipher, "Set cipher  (default 'AES256')", "<cipher:one of(AES256)>" },
{ "md", 0, 0, G_OPTION_ARG_STRING, &md, "Set md (default 'MD5')", "<md:one of (MD5)>" },
{ "salts", 0, 0, G_OPTION_ARG_INT, &salts, "Set salts (default 256)", "<salts:int>" },
{ "volumename", 0, 0, G_OPTION_ARG_STRING, &volume_name, "Set Finder volume name", "<volume name:string>" },
{ "volumeicon", 0, 0, G_OPTION_ARG_STRING, &custom_icon, "Set Finder volume icon", "<volume icon:string>" },
{ NULL }
};


typedef void (*freeFunc) (void *);

int main(int argc, char *argv[]) {
	return mkcryptomfs_main(argc, argv);
}

int mkcryptomfs_main(int argc, char *argv[])
{
    GError *error = NULL;
    GOptionContext *context;
	gchar *realRootpath;
	gchar *configPath;
	gchar *mountPath;
	int newFs = 0; // are we creating or modifying
	struct stat rootPathStat;
	int status;
	
	CryptomfsConfig config;
	bzero(&config, sizeof(CryptomfsConfig));
	setupDefaultConfig(&config);
	
    umask(0);
	
    context = g_option_context_new ("<.cryptofs package> [<mountpoint>]");
	g_option_context_set_ignore_unknown_options(context, FALSE);
    g_option_context_add_main_entries (context, entries, NULL);
    if(!g_option_context_parse (context, &argc, &argv, &error))
	{
		fprintf(stderr, "[mkcryptomfs] Error parsing options: %s\n", error->message);
		return 1;
	}
	
	/*
	 * Make sure we have at least one argument left.
	 * argv[1] = path to .crpytofs pacakge
	 * argv[2] = path to mountpoint (optional)
	 */
	if(argc < 2 || argc > 3) {
		fprintf(stderr, "%s\n", g_option_context_get_help(context, TRUE, NULL));
		return 1;
	}
	
	rootpath = argv[1];
	// make sure a root was given
    if (rootpath == NULL) {
		fprintf(stderr, "[mkcryptomfs] No path for encrypted directory specified (see --help)\n");
		return 1;
    }
	
	// check to make sure rootpath has .cryptofs extension
	if(!g_str_has_suffix(rootpath, CRYPT_PKG_SUFFIX)) {
		// add suffix to end of string
		g_strlcat(rootpath, CRYPT_PKG_SUFFIX, MAX_PATH);
	}
	
	// check if rootpath exists, if so we are editing not creating
	if(lstat((const char*)rootpath, &rootPathStat) < 0) 
	{
		if(errno == ENOENT) {
			newFs = 1;
		} else {
			fprintf(stderr, "[mkcryptomfs] I/O error - %s\n", strerror(errno));
			return 1;
		}
	}
	
	realRootpath = g_strjoin("/", rootpath, "crypt", NULL);
	configPath = g_strjoin("/", rootpath, "cryptofs.plist", NULL);
	mountPath = g_strjoin("/", rootpath, "mount", NULL);
	
	if(!newFs)
	{
		// read in current config
		if(!readConfig(configPath, &config))
		{
			fprintf(stderr, "[mkcryptomfs] Warning: Could not read config file at %s\n", configPath);
		}
	} else {
		// create root path
		status = mkdir((const char*)rootpath, S_IRWXU | S_IRGRP );
		if(status != 0) 
		{
			fprintf(stderr, "[mkcryptomfs] I/O error - %s\n", strerror(errno));
			return 1;
		}
		
		// create crypt directory
		status = mkdir((const char*)realRootpath, S_IRWXU | S_IRGRP );
		if(status != 0)
		{
			fprintf(stderr, "[mkcryptomfs] I/O error - %s\n", strerror(errno));
			return 1;
		}
		
		// create default mount directory
		status = mkdir((const char*)mountPath, S_IRWXU | S_IRGRP );
		if(status != 0)
		{
			fprintf(stderr, "[mkcryptomfs] I/O error - %s\n", strerror(errno));
			return 1;
		}
	}
	
	// command-line config options
	if(argc == 3) {
		mountpoint = argv[2];
		bzero(config.mountPath, MAX_PATH);
		strncpy(config.mountPath, mountpoint, strlen(mountpoint));
	}
	
	if(md != NULL) {
		bzero(config.md, MAXMDLENGTH);
		strncpy(config.md, md, strlen(md));
	}
	
	if(cipher != NULL) {
		bzero(config.cipher, MAXCIPHERLENGTH);
		strncpy(config.cipher, cipher, strlen(cipher));
	}
	
	if(blocksize > 0) {
		config.blocksize = blocksize;
	}
	
	if(salts > 0) {
		config.salts = salts;
	}
	
	if(volume_name != NULL) {
		bzero(config.volumeName, MAXVOLUMENAME);
		strncpy(config.volumeName, volume_name, strlen(volume_name));
	}
	
	if(custom_icon != NULL) {
		bzero(config.volumeIcon, MAX_PATH);
		strncpy(config.volumeIcon, custom_icon, strlen(custom_icon));
	}
		
	
	// save config
	writeConfig((const char*)configPath, &config);
	

	return 0;
}
	


